"""
Flask缓存示例 - 展示各种缓存策略和使用场景
包含Redis缓存、内存缓存、装饰器缓存等功能
"""

from flask import Flask, request, jsonify, g
import os
import sys
import time
import asyncio
from datetime import datetime, timedelta
from typing import List, Dict, Any, Optional

# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from python_backend_toolkit.cache import (
    RedisCache, MemoryCache, CacheService, 
    cached, cache_result, cache_user_data
)
from python_backend_toolkit.logging import get_logger
from python_backend_toolkit.utils import generate_uuid
from python_backend_toolkit.api.responses import SuccessResponse, ErrorResponse


def create_cache_app() -> Flask:
    """创建缓存示例Flask应用"""
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'cache-demo-secret'
    
    # 初始化缓存
    try:
        # 尝试连接Redis
        redis_cache = RedisCache(host='localhost', port=6379, db=1)
        cache_backend = redis_cache
        cache_type = "Redis"
    except Exception:
        # 如果Redis不可用，使用内存缓存
        cache_backend = MemoryCache()
        cache_type = "Memory"
    
    cache_service = CacheService(cache_backend)
    logger = get_logger("CacheApp")
    
    # 模拟数据
    MOCK_USERS = {
        1: {"id": 1, "name": "张三", "email": "zhangsan@example.com", "role": "admin"},
        2: {"id": 2, "name": "李四", "email": "lisi@example.com", "role": "user"},
        3: {"id": 3, "name": "王五", "email": "wangwu@example.com", "role": "user"},
    }
    
    MOCK_PRODUCTS = [
        {"id": i, "name": f"产品{i}", "price": 100 + i * 10, "category": f"分类{i % 3 + 1}"}
        for i in range(1, 101)
    ]
    
    @app.before_request
    def before_request():
        """请求前处理"""
        g.request_id = generate_uuid()
        g.start_time = time.time()
    
    @app.after_request
    def after_request(response):
        """请求后处理"""
        duration = time.time() - g.start_time
        logger.info(
            "Request completed",
            request_id=g.request_id,
            method=request.method,
            path=request.path,
            status_code=response.status_code,
            duration=duration
        )
        return response
    
    # ========================================================================
    # 基础缓存操作
    # ========================================================================
    
    @app.route('/cache/basic/set', methods=['POST'])
    def cache_set():
        """设置缓存"""
        data = request.get_json()
        key = data.get('key')
        value = data.get('value')
        ttl = data.get('ttl', 300)  # 默认5分钟
        
        if not key or value is None:
            return jsonify(ErrorResponse.create(
                message="Key and value are required"
            ).dict()), 400
        
        try:
            asyncio.run(cache_service.set(key, value, ttl=ttl))
            
            response = SuccessResponse.create(
                data={"key": key, "value": value, "ttl": ttl},
                message="Cache set successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            return jsonify(ErrorResponse.create(
                message=f"Failed to set cache: {str(e)}"
            ).dict()), 500
    
    @app.route('/cache/basic/get/<key>', methods=['GET'])
    def cache_get(key: str):
        """获取缓存"""
        try:
            value = asyncio.run(cache_service.get(key))
            
            if value is None:
                return jsonify(ErrorResponse.create(
                    message="Key not found in cache"
                ).dict()), 404
            
            response = SuccessResponse.create(
                data={"key": key, "value": value},
                message="Cache retrieved successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            return jsonify(ErrorResponse.create(
                message=f"Failed to get cache: {str(e)}"
            ).dict()), 500
    
    @app.route('/cache/basic/delete/<key>', methods=['DELETE'])
    def cache_delete(key: str):
        """删除缓存"""
        try:
            success = asyncio.run(cache_service.delete(key))
            
            response = SuccessResponse.create(
                data={"key": key, "deleted": success},
                message="Cache deleted successfully" if success else "Key not found"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            return jsonify(ErrorResponse.create(
                message=f"Failed to delete cache: {str(e)}"
            ).dict()), 500
    
    # ========================================================================
    # 装饰器缓存示例
    # ========================================================================
    
    @cached(expire=60, key_func=lambda user_id: f"user_profile:{user_id}")
    async def get_user_profile(user_id: int) -> Optional[Dict]:
        """获取用户资料（模拟数据库查询）"""
        # 模拟数据库查询延迟
        await asyncio.sleep(0.5)
        return MOCK_USERS.get(user_id)
    
    @app.route('/cache/users/<int:user_id>', methods=['GET'])
    def get_cached_user(user_id: int):
        """获取用户信息（带缓存）"""
        start_time = time.time()
        
        try:
            user = asyncio.run(get_user_profile(user_id))
            
            if not user:
                return jsonify(ErrorResponse.create(
                    message="User not found"
                ).dict()), 404
            
            query_time = time.time() - start_time
            
            response = SuccessResponse.create(
                data={
                    "user": user,
                    "query_time": round(query_time, 3),
                    "cached": query_time < 0.1  # 如果查询时间很短，说明使用了缓存
                },
                message="User retrieved successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            return jsonify(ErrorResponse.create(
                message=f"Failed to get user: {str(e)}"
            ).dict()), 500
    
    # ========================================================================
    # 结果缓存示例
    # ========================================================================
    
    @cache_result(expire=120)
    async def expensive_calculation(numbers: List[int]) -> Dict[str, Any]:
        """耗时计算（模拟复杂业务逻辑）"""
        # 模拟复杂计算
        await asyncio.sleep(1.0)
        
        total = sum(numbers)
        average = total / len(numbers) if numbers else 0
        maximum = max(numbers) if numbers else 0
        minimum = min(numbers) if numbers else 0
        
        return {
            "total": total,
            "average": round(average, 2),
            "maximum": maximum,
            "minimum": minimum,
            "count": len(numbers),
            "calculated_at": datetime.utcnow().isoformat()
        }
    
    @app.route('/cache/calculate', methods=['POST'])
    def cached_calculation():
        """执行缓存计算"""
        data = request.get_json()
        numbers = data.get('numbers', [])
        
        if not isinstance(numbers, list) or not all(isinstance(n, (int, float)) for n in numbers):
            return jsonify(ErrorResponse.create(
                message="Numbers must be a list of integers or floats"
            ).dict()), 400
        
        start_time = time.time()
        
        try:
            result = asyncio.run(expensive_calculation(numbers))
            calculation_time = time.time() - start_time
            
            response = SuccessResponse.create(
                data={
                    "result": result,
                    "calculation_time": round(calculation_time, 3),
                    "cached": calculation_time < 0.5
                },
                message="Calculation completed successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            return jsonify(ErrorResponse.create(
                message=f"Calculation failed: {str(e)}"
            ).dict()), 500
    
    # ========================================================================
    # 用户数据缓存示例
    # ========================================================================
    
    @cache_user_data(expire=300)
    async def get_user_dashboard_data(user_id: int) -> Dict[str, Any]:
        """获取用户仪表板数据"""
        # 模拟多个数据源查询
        await asyncio.sleep(0.8)
        
        user = MOCK_USERS.get(user_id)
        if not user:
            return None
        
        # 模拟用户统计数据
        stats = {
            "total_orders": user_id * 5,
            "total_spent": user_id * 1000,
            "favorite_category": f"分类{user_id % 3 + 1}",
            "last_login": (datetime.utcnow() - timedelta(hours=user_id)).isoformat(),
            "notifications": user_id * 2,
            "points": user_id * 100
        }
        
        return {
            "user": user,
            "stats": stats,
            "generated_at": datetime.utcnow().isoformat()
        }
    
    @app.route('/cache/dashboard/<int:user_id>', methods=['GET'])
    def get_user_dashboard(user_id: int):
        """获取用户仪表板（带缓存）"""
        start_time = time.time()
        
        try:
            dashboard_data = asyncio.run(get_user_dashboard_data(user_id))
            
            if not dashboard_data:
                return jsonify(ErrorResponse.create(
                    message="User not found"
                ).dict()), 404
            
            load_time = time.time() - start_time
            
            response = SuccessResponse.create(
                data={
                    "dashboard": dashboard_data,
                    "load_time": round(load_time, 3),
                    "cached": load_time < 0.3
                },
                message="Dashboard data retrieved successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            return jsonify(ErrorResponse.create(
                message=f"Failed to load dashboard: {str(e)}"
            ).dict()), 500
    
    # ========================================================================
    # 列表数据缓存示例
    # ========================================================================
    
    @cached(expire=180, key_func=lambda category, page, size: f"products:{category}:{page}:{size}")
    async def get_products_by_category(category: str, page: int = 1, size: int = 10) -> Dict[str, Any]:
        """根据分类获取产品列表"""
        # 模拟数据库查询
        await asyncio.sleep(0.3)
        
        # 过滤产品
        filtered_products = [p for p in MOCK_PRODUCTS if p['category'] == category]
        
        # 分页
        start = (page - 1) * size
        end = start + size
        page_products = filtered_products[start:end]
        
        return {
            "products": page_products,
            "total": len(filtered_products),
            "page": page,
            "size": size,
            "pages": (len(filtered_products) + size - 1) // size,
            "has_next": end < len(filtered_products),
            "has_prev": page > 1
        }
    
    @app.route('/cache/products', methods=['GET'])
    def get_cached_products():
        """获取产品列表（带缓存）"""
        category = request.args.get('category', '分类1')
        page = int(request.args.get('page', 1))
        size = min(int(request.args.get('size', 10)), 50)
        
        start_time = time.time()
        
        try:
            products_data = asyncio.run(get_products_by_category(category, page, size))
            query_time = time.time() - start_time
            
            response = SuccessResponse.create(
                data={
                    **products_data,
                    "query_time": round(query_time, 3),
                    "cached": query_time < 0.1
                },
                message="Products retrieved successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            return jsonify(ErrorResponse.create(
                message=f"Failed to get products: {str(e)}"
            ).dict()), 500
    
    # ========================================================================
    # 缓存管理和统计
    # ========================================================================
    
    @app.route('/cache/stats', methods=['GET'])
    def cache_stats():
        """获取缓存统计信息"""
        try:
            stats = asyncio.run(cache_service.get_stats())
            
            response = SuccessResponse.create(
                data={
                    "cache_type": cache_type,
                    "stats": stats,
                    "timestamp": datetime.utcnow().isoformat()
                },
                message="Cache statistics retrieved successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            return jsonify(ErrorResponse.create(
                message=f"Failed to get cache stats: {str(e)}"
            ).dict()), 500
    
    @app.route('/cache/clear', methods=['POST'])
    def clear_cache():
        """清空缓存"""
        pattern = request.args.get('pattern', '*')
        
        try:
            cleared_count = asyncio.run(cache_service.clear(pattern))
            
            response = SuccessResponse.create(
                data={
                    "pattern": pattern,
                    "cleared_count": cleared_count
                },
                message=f"Cache cleared successfully. {cleared_count} keys removed."
            )
            return jsonify(response.dict())
            
        except Exception as e:
            return jsonify(ErrorResponse.create(
                message=f"Failed to clear cache: {str(e)}"
            ).dict()), 500
    
    # ========================================================================
    # 缓存预热示例
    # ========================================================================
    
    @app.route('/cache/warmup', methods=['POST'])
    def warmup_cache():
        """缓存预热"""
        try:
            # 预热用户数据
            for user_id in MOCK_USERS.keys():
                asyncio.run(get_user_profile(user_id))
                asyncio.run(get_user_dashboard_data(user_id))
            
            # 预热产品数据
            categories = ["分类1", "分类2", "分类3"]
            for category in categories:
                asyncio.run(get_products_by_category(category, 1, 10))
            
            response = SuccessResponse.create(
                data={
                    "warmed_users": len(MOCK_USERS),
                    "warmed_categories": len(categories)
                },
                message="Cache warmup completed successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            return jsonify(ErrorResponse.create(
                message=f"Cache warmup failed: {str(e)}"
            ).dict()), 500
    
    # ========================================================================
    # 应用信息
    # ========================================================================
    
    @app.route('/health', methods=['GET'])
    def health_check():
        """健康检查"""
        return jsonify({
            "status": "healthy",
            "cache_type": cache_type,
            "timestamp": datetime.utcnow().isoformat()
        })
    
    @app.route('/info', methods=['GET'])
    def app_info():
        """应用信息"""
        return jsonify({
            "name": "Flask Cache Example",
            "version": "1.0.0",
            "description": "Flask缓存功能示例应用",
            "cache_backend": cache_type,
            "endpoints": {
                "basic_cache": [
                    "POST /cache/basic/set",
                    "GET /cache/basic/get/<key>",
                    "DELETE /cache/basic/delete/<key>"
                ],
                "decorator_cache": [
                    "GET /cache/users/<id>",
                    "POST /cache/calculate",
                    "GET /cache/dashboard/<id>",
                    "GET /cache/products"
                ],
                "management": [
                    "GET /cache/stats",
                    "POST /cache/clear",
                    "POST /cache/warmup"
                ]
            }
        })
    
    return app


if __name__ == '__main__':
    app = create_cache_app()
    
    print("=" * 60)
    print("Flask Cache Example")
    print("=" * 60)
    print("缓存功能演示:")
    print("  基础缓存操作:")
    print("    POST /cache/basic/set - 设置缓存")
    print("    GET  /cache/basic/get/<key> - 获取缓存")
    print("    DELETE /cache/basic/delete/<key> - 删除缓存")
    print()
    print("  装饰器缓存:")
    print("    GET  /cache/users/<id> - 获取用户信息（带缓存）")
    print("    POST /cache/calculate - 执行计算（带缓存）")
    print("    GET  /cache/dashboard/<id> - 获取用户仪表板（带缓存）")
    print("    GET  /cache/products - 获取产品列表（带缓存）")
    print()
    print("  缓存管理:")
    print("    GET  /cache/stats - 获取缓存统计")
    print("    POST /cache/clear - 清空缓存")
    print("    POST /cache/warmup - 缓存预热")
    print("=" * 60)
    
    app.run(
        host='0.0.0.0',
        port=5001,
        debug=True
    )